/*
 * @Description: 基于事件发布订阅模式模拟 event-bus进行组件通信
 * @Version: 1.0.0
 * @Author: gyh
 * @Date: 2021-08-22 15:11:01
 * @LastEditors: gyh
 * @LastEditTime: 2021-08-22 15:46:26
 */
class EventEmitter {
  constructor() {
    this._events = this._events || new Map() // 存储事件、回调键值对
    this._maxListeners = this._maxListeners || 10 // 设立监听上限
  }
}
// 触发 type 的事件
EventEmitter.prototype.emit = function (type, ...args) {
  let handler
  handler = this._events.get(type)
  if (Array.isArray(handler)) {
    // 如果是一个数组说明有多个监听者，需要依次触发里面的函数
    for (let i = 0; i < handler.length; i++) {
      args.length > 0 ? handler[i].apply(this, args) : handler[i].call(this)
    }
  } else {
    // 单个函数的情况直接触发即可
    args.length > 0 ? handler.apply(this, args) : handler.call(this)
  }
  return true
}
// 监听 type 的事件
EventEmitter.prototype.addListener = function (type, fn) {
  const handler = this._events.get(type) // // 获取对应事件名称的函数清单
  if (!handler) {
    // 如果 handler 不存在
    this._events.set(type, fn)
  } else if (handler && typeof handler === 'function') {
    // 如果 handler 是函数说明只有一个监听者
    this._events.set(type, [handler, fn])
  } else {
    // 已经有多个监听者,那么直接往数组里push函数即可
    handler.push(fn)
  }
}
// 移除监听
EventEmitter.prototype.removeListener = function (type, fn) {
  const handler = this._events.get(type)
  if (handler && typeof handler === 'function') {
    // 如果是函数说明只监听了一次
    this._events.delete(type, fn)
  } else {
    const position
    // 如果 handler 是数组,说明被监听多次要找到对应的函数
    for (let i = 0; i < handler.length; i++) {
      position = handler[i] === fn ? i : -1
    }
    // 如果找到匹配的函数,从数组中清除
    if (position !== -1) {
      handler.splice(position, 1) // 找到数组对应的位置,直接清除此回调
      if (handler.length === 1) {
        this._events.set(type, handler[0]);
      }
    } else {
      return this
    }
  }
}

const emitter = new EventEmitter()
emitter.addListener('say', () => {
  console.log('hello')
})
emitter.addListener('say', man => {
  console.log(`${man} speek`)
})
emitter.emit('say', '张三')
